﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Reflection;

namespace SPMS.Utility
{
    /// <summary>
    /// 强制强名验证
    /// </summary>
    /// <remarks>https://10.32.0.90/leyser/bin/view/Main/HybridQuestionsStrongName</remarks>
    /// <history>
    /// [CaiShengRong]   2009/4/13 11:19    Created  您的潜力，俺的动力
    /// </history>
    public static class StrongNameSignatureVerification
    {
        /// <summary>
        /// Determines whether strong name signature verification ex suessfully.
        /// </summary>
        /// <param name="wszFilePath">The WSZ file path.</param>
        /// <param name="fForceVerification">if set to <c>true</c> [f force verification].</param>
        /// <param name="pfWasVerified">if set to <c>true</c> [pf was verified].</param>
        /// <returns>
        /// 	<c>true</c> if strong name signature verification ex successfully; otherwise, <c>false</c>.
        /// </returns>
        /// <remarks></remarks>
        /// <history>
        /// [CaiShengRong]   2009/4/13 10:48    Created  您的潜力，俺的动力
        /// </history>
        [DllImport( "mscoree.dll", CharSet = CharSet.Unicode )]
        static extern bool StrongNameSignatureVerificationEx( string wszFilePath, bool fForceVerification, out bool pfWasVerified );


        //        The parameters can be little confusing, so let me provide a short explanation.  wszFilePath is, as you would expect, the path to the file that is to be checked.  fForceVerification is a boolean flag that tells StrongNameSignatureVerificationEx if it should set the pfWasVerified output flag.  The return value from the API is true if the strong name is valid, false otherwise.

        //fForceVerification and pfWasVerified work together to allow you to use the skip verification list.  (More details on this can be found in my post on delay signing).  If you pass false to fForceVerification, StrongNameSignatureVerificationEx will consult the skip verification list, and the return value of the API call will be true if the assembly was on the list.  However, since no verification was actually performed, the pfWasVerified flag will be set to false.  pfWasVerified is only set if fForceVerification is set to false, if you pass true to this parameter, pfWasVerified will be meaningless.

        //It's a little easier to think of it this way.  StrongNameSignatureVerificationEx will by default consult the skip verification list, and return true if the assembly is on that list.  If you really want to force the issue, pass true into fForceVerification in order to force the API into actually doing the signature check on the input assembly.


        //    Here's some scenarios that might help to clarify:

        //                          fForceVerification 	fWasVerified 	Return Value
        //Strongly Named Assembly 	        true 	        true 	        true
        //Strongly Named and Tampered With 	true 	        false 	        false
        //Delay Signed, Skip Verification 	true 	        false 	        false
        //Strongly Named Assembly 	        false 	        true 	        true
        //Strongly Named and Tampered With 	false 	        false 	        false
        //Delay Signed, Skip Verification 	false 	        false 	        true

        /// <summary>
        /// Initializes the <see cref="StrongNameSignatureVerification"/> class.
        /// </summary>
        /// <remarks></remarks>
        /// <history>
        /// [CaiShengRong]   2009/4/13 10:40    Created  您的潜力，俺的动力
        /// </history>
        static StrongNameSignatureVerification()
        {


        }

        /// <summary>
        /// 强制验证强名
        /// </summary>
        /// <param name="assembly">The assembly.</param>
        /// <remarks></remarks>
        /// <history>
        /// [CaiShengRong]   2009/4/13 10:53    Created  您的潜力，俺的动力
        /// </history>
        public static void Verification( this Assembly assembly )
        {
            ArgumentAssert.AssertArgumentNotNull( assembly, "assembly" );

            string filePath = assembly.Location;

            Verification( filePath );
        }

        /// <summary>
        /// 强制验证强名
        /// </summary>
        /// <param name="assemblyFilePath">要验证强签名的程序的路径。</param>
        /// <remarks></remarks>
        /// <exception cref="ArgumentNullException"><paramref name="assemblyFilePath"/>为<c>null</c>或者为空字符串。</exception>
        /// <history>
        /// [CaiShengRong]   2009/4/13 10:54    Created  您的潜力，俺的动力
        /// </history>
        public static void Verification(this string assemblyFilePath)
        {
#if DEBUG
            return;
#else 
            
            //断言参数
            ArgumentAssert.AssertArgumentNotNull(assemblyFilePath, "filePath");

            // check the signature first
            bool wasVerified = false;

            //强制验证
            bool verified = StrongNameSignatureVerificationEx(assemblyFilePath, true, out wasVerified);

            if (!verified)
            {
                throw new BadImageFormatException( string.Format( "Assembly  Verification failed!" ) );
            }   
#endif
        }

        /// <summary>
        /// 强制验证强名
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <remarks></remarks>
        /// <history>
        /// [CaiShengRong]   2009/4/13 11:36    Created  您的潜力，俺的动力
        /// </history>
        public static void Verification<T>( this T t )
        {

            Verification( Assembly.GetExecutingAssembly() );

            Verification<T>();
        }

        /// <summary>
        /// 强制验证强名
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <remarks></remarks>
        /// <history>
        /// [CaiShengRong]   2009/4/13 11:46    Created  您的潜力，俺的动力
        /// </history>
        public static void Verification<T>()
        {

            Verification( Assembly.GetExecutingAssembly() );

            Verification( typeof( T ).Assembly );
        }

        /// <summary>
        /// 强制验证强名
        /// </summary>
        /// <param name="type">The type.</param>
        /// <remarks></remarks>
        /// <history>
        /// [CaiShengRong]   2009/4/13 14:18    Created  您的潜力，俺的动力
        /// </history>
        public static void Verification( this Type type )
        {

            Verification( Assembly.GetExecutingAssembly() );

            Verification( type.Assembly );
        }

    }
}
